import re


class M4MacroParser:

    def parse_m4_macros(self, input):
        input = self.remove_comments(input)
        input = self.remove_here_documents(input)
        input = self.merge_lines(input)
        index = 0
        macros = []

        while index < len(input):
            match = re.search(r'\b([A-Z_]+|m4_[a-z_]+)\(', input[index:])
            if match:
                macro_name = match.group(1)
                macro = self.parse_macro(input, index + match.start(0), macro_name)
                index += match.end(0)
                macros.append(macro)
            else:
                break

        return macros

    def parse_macro(self, input, index, macro_name):
        params = []
        index += len(macro_name) + 1

        while index < len(input):    
            param = self.parse_param(input, index)
            index += len(param)
            param = param.strip()
            if len(param) > 0 and param[0] == '[' and param[-1] == ']':
                param = param[1:-1]
            params.append(param)
            if index < len(input) and input[index] == ')':
                break
            index += 1

        return {
            "macro_name": macro_name,
            "macro_params": params
        }

    def parse_param(self, input, index):
        brackets_depth = 0
        parentheses_depth = 0
        i = index

        while i < len(input):
            char = input[i]
            if char == '[':
                brackets_depth += 1
            elif char == ']' and brackets_depth > 0:
                brackets_depth -= 1
            elif char == '(':
                parentheses_depth += 1
            elif char == ')' and parentheses_depth > 0:
                parentheses_depth -= 1
            elif char == ',' and brackets_depth == 0 and parentheses_depth == 0:
                break
            elif char == ')' and brackets_depth == 0 and parentheses_depth == 0:
                break
            i += 1

        return input[index:i]

    def remove_comments(self, code):
        return re.sub(r'\s#.*$', '', re.sub(r'dnl.*$', '', code, flags=re.MULTILINE), flags=re.MULTILINE)

    def remove_here_documents(self, code):
        return re.sub(
            r'<<-?\s*["\'`]([^\s"\'`]+)["\'`]?.*?^\s*\1$',
            lambda match: 'HERE-DOCUMENT',
            code,
            flags=re.MULTILINE
        )

    def merge_lines(self, code):
        return code.replace('\\\n', '')

# if __name__=='__main__':
#     # Usage
#     parser = M4MacroParser()
#     input_file = open('code/autoconf_examples/glibc/configure.ac')
#     input_code = input_file.read()
#     result = parser.parse_m4_macros(input_code)
#     print(len(result))
